// Copyright (c) 2021 Tencent. All rights reserved.
// Author: tatemin

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:tencent_calls_engine/tuicall_observer.dart';

import 'tuicall_engine_platform_interface.dart';
import 'package:tencent_calls_engine/tuicall_define.dart';

/// An implementation of [TUICallEnginePlatform] that uses method channels.
class MethodChannelTUICallEngine extends TUICallEnginePlatform {
  final List<TUICallObserver> _observerList = [];

  @visibleForTesting
  final methodChannel = const MethodChannel('tuicall_engine');

  MethodChannelTUICallEngine() {
    methodChannel.setMethodCallHandler((call) async {
      if (call.method == "onTUICallObserver") {
        String observerName = call.arguments['method'];
        var observerParams = call.arguments['params'];

        _onTUICallObserver(observerName, observerParams);
      } else {
        debugPrint("onTUICallObserver: MethodNotImplemented ${call.arguments}");
      }
    });
  }

  @override
  Future<void> addObserver(TUICallObserver observer) async {
    _observerList.add(observer);
    methodChannel.invokeMethod("addObserver", {});
  }

  @override
  Future<void> removeObserver(TUICallObserver observer) async {
    _observerList.remove(observer);
    if (_observerList.isEmpty) {
      methodChannel.invokeMethod("removeObserver", {});
    }
  }

  void _onTUICallObserver(String observerName, var params) {
    for (var observer in _observerList) {
      switch (observerName) {
        case "onError":
          {
            observer.onError != null
                ? observer.onError!(params["code"], params['message'])
                : false;
            break;
          }

        case "onCallReceived":
          {
            TUICallMediaType callMediaType =
                TUICallMediaType.values[params['callMediaType']];
            observer.onCallReceived != null
                ? observer.onCallReceived!(
                    params['callerId'],
                    params['calleeIdList'] as List<String>,
                    params['groupId'],
                    callMediaType)
                : false;
            break;
          }

        case "onCallCancelled":
          {
            observer.onCallCancelled != null
                ? observer.onCallCancelled!(params['callerId'])
                : false;
            break;
          }

        case "onCallBegin":
          {
            final roomIdMap = Map<String, int>.from(params['roomId']);
            TUIRoomId roomId = TUIRoomId(intRoomId: roomIdMap['intRoomId']!);
            TUICallMediaType callMediaType =
                TUICallMediaType.values[params['callMediaType']];
            TUICallRole callRole = TUICallRole.values[params['callRole']];
            observer.onCallBegin != null
                ? observer.onCallBegin!(roomId, callMediaType, callRole)
                : false;
            break;
          }

        case "onCallEnd":
          {
            TUIRoomId roomId =
                TUIRoomId(intRoomId: params['roomId']['intRoomId']);
            TUICallMediaType callMediaType =
                TUICallMediaType.values[params['callMediaType']];
            TUICallRole callRole = TUICallRole.values[params['callRole']];
            double totalTime = params['totalTime'];
            observer.onCallEnd != null
                ? observer.onCallEnd!(
                    roomId, callMediaType, callRole, totalTime)
                : false;
            break;
          }

        case "onCallMediaTypeChanged":
          {
            TUICallMediaType oldCallMediaType =
                TUICallMediaType.values[params['oldCallMediaType']];
            TUICallMediaType newCallMediaType =
                TUICallMediaType.values[params['newCallMediaType']];
            observer.onCallMediaTypeChanged != null
                ? observer.onCallMediaTypeChanged!(
                    oldCallMediaType, newCallMediaType)
                : false;
            break;
          }

        case "onUserReject":
          {
            observer.onUserReject != null
                ? observer.onUserReject!(params['userId'])
                : false;
            break;
          }

        case "onUserNoResponse":
          {
            observer.onUserNoResponse != null
                ? observer.onUserNoResponse!(params['userId'])
                : false;
            break;
          }

        case "onUserLineBusy":
          {
            observer.onUserLineBusy != null
                ? observer.onUserLineBusy!(params['userId'])
                : false;
            break;
          }

        case "onUserJoin":
          {
            observer.onUserJoin != null
                ? observer.onUserJoin!(params['userId'])
                : false;
            break;
          }

        case "onUserLeave":
          {
            observer.onUserLeave != null
                ? observer.onUserLeave!(params['userId'])
                : false;
            break;
          }

        case "onUserVideoAvailable":
          {
            observer.onUserVideoAvailable != null
                ? observer.onUserVideoAvailable!(
                    params['userId'], params['isVideoAvailable'])
                : false;
            break;
          }

        case "onUserAudioAvailable":
          {
            observer.onUserAudioAvailable != null
                ? observer.onUserAudioAvailable!(
                    params['userId'], params['isAudioAvailable'])
                : false;
            break;
          }

        case "onUserVoiceVolumeChanged":
          {
            final volumeMap = Map<String, int>.from(params['volumeMap']);
            observer.onUserVoiceVolumeChanged != null
                ? observer.onUserVoiceVolumeChanged!(volumeMap)
                : false;
            break;
          }

        case "onUserNetworkQualityChanged":
          {
            List returnNetworkQualityList = params['networkQualityList'];
            List<TUINetworkQualityInfo> networkQualityLists = [];
            for (final element in returnNetworkQualityList) {
              var userId = (element['userId'] == null) ? "" : element['userId'];
              TUINetworkQuality quality =
                  TUINetworkQuality.values[element["networkQuality"]];
              networkQualityLists
                  .add(TUINetworkQualityInfo(userId: userId, quality: quality));
            }
            observer.onUserNetworkQualityChanged != null
                ? observer.onUserNetworkQualityChanged!(networkQualityLists)
                : false;
            break;
          }

        case "onKickedOffline":
          {
            observer.onKickedOffline != null
                ? observer.onKickedOffline!()
                : false;
            break;
          }

        case "onUserSigExpired":
          {
            observer.onUserSigExpired != null
                ? observer.onUserSigExpired!()
                : false;
            break;
          }
      }
    }
  }
}
